package com.vogue.flowmeter.profile;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.vogue.flowmeter.BaseApplication;
import com.vogue.flowmeter.api.entity.ApiRecordEntity;
import com.vogue.flowmeter.api.entity.BaseResponse;
import com.vogue.flowmeter.api.event.MessageEvent;
import com.vogue.flowmeter.api.event.MessageExternalEvent;
import com.vogue.flowmeter.api.event.MessageUpdateEvent;
import com.vogue.flowmeter.api.retrofit.NetWorkManager;
import com.vogue.flowmeter.profile.callback.VogueBleReadAndWriteCallback;
import com.vogue.flowmeter.util.ConvertUtils;
import com.vogue.flowmeter.util.PrefsUtils;

import org.greenrobot.eventbus.EventBus;

import java.util.Date;
import java.util.UUID;

import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DefaultObserver;
import io.reactivex.schedulers.Schedulers;
import no.nordicsemi.android.ble.WriteRequest;
import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.ble.livedata.ObservableBleManager;
import no.nordicsemi.android.log.LogContract;
import no.nordicsemi.android.log.LogSession;
import no.nordicsemi.android.log.Logger;

/**
 * 蓝牙管理器
 */
public class BleProfileManager  extends ObservableBleManager {

    public final static UUID VOGUE_UUID_SERVICE = UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
    //写入
    private final static UUID VOGUE_UUID_WRITE_CHAR = UUID.fromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
    //读取(收取通知)
    private final static UUID VOGUE_UUID_NOTIFY_CHAR = UUID.fromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e");

    private BluetoothGattCharacteristic txCharacteristic, rxCharacteristic;

    private LogSession logSession;
    private boolean supported;
    private boolean useLongWrite = true;

    public BleProfileManager(Context context) {
        super(context);
    }

    public BleProfileManager(Context context, Handler handler) {
        super(context, handler);
    }


    @Nullable
    @Override
    public BluetoothDevice getBluetoothDevice() {

        return super.getBluetoothDevice();
    }

    /**
     * Sets the log session to be used for low level logging.
     * @param session the session, or null, if nRF Logger is not installed.
     */
    public void setLogger(@Nullable final LogSession session) {
        logSession = session;
    }

    @Override
    public void log(final int priority, @NonNull final String message) {
        // The priority is a Log.X constant, while the Logger accepts it's log levels.
        Logger.log(logSession, LogContract.Log.Level.fromPriority(priority), message);
    }
    @Override
    protected boolean shouldClearCacheWhenDisconnected() {
        return !supported;
    }

    @NonNull
    @Override
    protected BleManagerGattCallback getGattCallback() {
        return new VogueBleManagerGattCallback();
    }


    /**
     * BluetoothGatt回调对象。
     */
    private class VogueBleManagerGattCallback extends BleManagerGattCallback {

        @Override
        protected boolean isOptionalServiceSupported(@NonNull BluetoothGatt gatt) {
            super.isOptionalServiceSupported(gatt);
            final BluetoothGattService service = gatt.getService(VOGUE_UUID_SERVICE);
            if (service != null) {
                txCharacteristic = service.getCharacteristic(VOGUE_UUID_NOTIFY_CHAR);
                rxCharacteristic = service.getCharacteristic(VOGUE_UUID_WRITE_CHAR);
            }
            return rxCharacteristic != null;
        }

        @Override
        public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
            Log.e("GattCallback","isRequiredServiceSupported");

            final BluetoothGattService service = gatt.getService(VOGUE_UUID_SERVICE);
            if (service != null) {
                txCharacteristic = service.getCharacteristic(VOGUE_UUID_NOTIFY_CHAR);
                rxCharacteristic = service.getCharacteristic(VOGUE_UUID_WRITE_CHAR);
            }

            boolean writeRequest = false;

            boolean notifyRequest = false;

            if (txCharacteristic != null) {
                final int rxProperties = txCharacteristic.getProperties();
                notifyRequest = (rxProperties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0;
            }

            if (rxCharacteristic != null) {
                final int rxProperties = rxCharacteristic.getProperties();
                writeRequest = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0;
            }

            if (writeRequest){
                rxCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
            }else {
                useLongWrite=false;
            }

            supported = txCharacteristic != null && rxCharacteristic != null && writeRequest&&notifyRequest;
            return supported;
        }

        @Override
        protected void onDeviceDisconnected() {
            Log.e("GattCallback","onDeviceDisconnected");

            txCharacteristic = null;
            rxCharacteristic = null;
            useLongWrite=true;


            MessageEvent conEvent=new MessageEvent("connection","connection","连接中断了");
            EventBus.getDefault().post(conEvent);

        }

        @Override
        protected void initialize() {
            Log.e("GattCallback","initialize");
            //mtu 需要判断蓝牙支持版本 做好适配
            requestMtu(517).enqueue();

            //通知(读)
            enableNotifications(txCharacteristic).enqueue();
            setNotificationCallback(txCharacteristic).with(bleReadAndWriteCallback);
            //写
            readCharacteristic(rxCharacteristic).with(bleReadAndWriteCallback).enqueue();
        }
    }

    /**
     * 读的回调
     */
    private	final VogueBleReadAndWriteCallback bleReadAndWriteCallback = new VogueBleReadAndWriteCallback() {

        @Override
        public void onMessageEvent(String direction,String operator, String control, String message,String data) {

            //判断数据是否正确  做本地缓存
            //PrefsUtils.getInstance(getContext()).put(operator,message);


            if ("ea".equals(operator)){
                //外部设置指令  发送事件出去

                int length=Integer.parseInt(data.substring(14,18),16)*2;

                String p= ConvertUtils.hexStr2Str(data.substring(18,18+length));

                String address=p.substring(0,4);

                MessageExternalEvent event = new MessageExternalEvent(operator,control,message,getData(data),address,direction);
                EventBus.getDefault().post(event);

            }else if ("e0".equals(operator)||"e1".equals(operator)){

               //升级指令  发送事件出去
                int line =Integer.parseInt(data.substring(18,22), 16);
                int lines=Integer.parseInt(data.substring(22,26), 16);
                int progress=(int)(Math.floor((line/(double)lines)*100));

                MessageUpdateEvent event = new MessageUpdateEvent(operator,control,message,getData(data),direction,progress,line,lines);
                EventBus.getDefault().post(event);

            }else {
                //其他指令   发送事件出去
                MessageEvent event = new MessageEvent(operator,control,message,getData(data),direction);
                EventBus.getDefault().post(event);
            }

            //保存记录
            saveRecord(control,getData(data));


        }

        /**
         * 解析返回数据
         * @param data
         * @return
         */
        private String getData(String data){

            int length=Integer.parseInt(data.substring(14,18),16)*2;
            return new Builder(data)
                    .setHeader(data.substring(0,2))
                    .setIdentification(data.substring(2,6))
                    .setDirection(data.substring(6,8))
                    .setAddress(data.substring(8,10))
                    .setEncryption(data.substring(10,12))
                    .setControl(data.substring(12,14))
                    .setDataLength(length+"")
                    .setData(data.substring(18,18+length))
                    .setChecksum(data.substring(18+length,18+length+2))
                    .setEnd(data.substring(18+length+2,18+length+4))
                    .toString();
        }

        /**
         * 保存记录
         * @param control
         * @param data
         */
        public void saveRecord(String control, String data){
            ApiRecordEntity apiRecord=new ApiRecordEntity();
            apiRecord.setCreateTime(new Date().getTime());
            apiRecord.setData(data);
            apiRecord.setOperationName(control);
            String deviceId= PrefsUtils.getInstance(BaseApplication.getInstance()).get("deviceId","");
            if(TextUtils.isEmpty(deviceId)){
                return;
            }
            apiRecord.setDeviceId(deviceId);
            NetWorkManager
                    .getInstance()
                    .getBleApiService()
                    .saveRecord(apiRecord)
                    .subscribeOn(Schedulers.io())
                    .doOnSubscribe(disposable -> {

                    })
                    .subscribeOn(AndroidSchedulers.mainThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new DefaultObserver<BaseResponse>() {
                        @Override
                        public void onNext(BaseResponse response) {
                            Log.e(BleProfileManager.class.getName(),response.getMsg());
                        }

                        @Override
                        public void onError(Throwable e) {
                            Log.e(BleProfileManager.class.getName(),e.getMessage());

                        }

                        @Override
                        public void onComplete() {

                        }
                    });
        }

    };


    /**
     * 写 读数据
     * @param data
     */
    public void readAndWriteData(Data data){

        writeCharacteristic(rxCharacteristic,data).with(bleReadAndWriteCallback).enqueue();

    }


    /**
     * 长数据写
     * @param msg the text to be sent
     */
    public void send(final Data msg) {
        // Are we connected?
        if (rxCharacteristic == null)
            return;
        final WriteRequest request = writeCharacteristic(rxCharacteristic, msg.getValue()).with((device, data) -> log(LogContract.Log.Level.APPLICATION,"\"" + data.getStringValue(0) + "\" sent"));
        if (!useLongWrite) {
            // This will automatically split the long data into MTU-3-byte long packets.
            request.split();
        }
        request.enqueue();
    }


    /**
     * 协议构造器
     */
    public static class Builder {

        //帧头
        private String header;
        //设备标识
        private String identification;
        //传输方向
        private String direction;
        //地址
        private String address;
        //加密版本
        private String encryption;
        //控制字
        private String control;
        //数据长度
        private String dataLength;
        //数据
        private String data;
        //校验和
        private String checksum;
        //帧尾
        private String end;

        //原始数据
        private String original;

        public Builder(String original) {
            this.original=original;
        }

        public Builder setHeader(String header) {
            this.header = header;
            return this;
        }

        public Builder setIdentification(String identification) {
            this.identification = identification;
            return this;
        }

        public Builder setDirection(String direction) {
            this.direction = direction;
            return this;
        }

        public Builder setAddress(String address) {
            this.address = address;
            return this;
        }

        public Builder setEncryption(String encryption) {
            this.encryption = encryption;
            return this;
        }

        public Builder setControl(String control) {
            this.control = control;
            return this;
        }

        public Builder setDataLength(String dataLength) {
            this.dataLength = dataLength;
            return this;
        }

        public Builder setData(String data) {
            this.data = data;
            return this;
        }

        public Builder setChecksum(String checksum) {
            this.checksum = checksum;
            return this;
        }

        public Builder setEnd(String end) {
            this.end = end;
            return this;
        }

        @Override
        public String toString() {
            return "{" +
                    "帧头='" + header + '\'' +
                    ", 设备标识='" + identification + '\'' +
                    ", 传输方向='" + direction + '\'' +
                    ", 地址='" + address + '\'' +
                    ", 加密版本='" + encryption + '\'' +
                    ", 控制字='" + control + '\'' +
                    ", 数据长度='" + dataLength + '\'' +
                    ", 数据='" + data + '\'' +
                    ", 校验和='" + checksum + '\'' +
                    ", 帧尾='" + end + '\'' +'}'+
                    " {" +"原始数据='" + original + '\''+'}';
        }
    }
}
